﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Perovich.GameObjects.Interfaces;
using Perovich.GameObjects.Attributes;
using Microsoft.Xna.Framework;

namespace Perovich.GameObjects.Components
{
    /// <summary>
    /// Represents the base of a component. 
    /// </summary>
    /// <remarks>
    /// A Component defines a specific functionality that can be attached to an Entity.
    /// Some examples are controllers (logic, AI), rendering and physics.
    /// </remarks>
    public abstract class EntityComponent : IEntityComponent
    {
        IEntity owner;

        int updateOrder;

        bool enabled = true;

        #region IEntityComponent Members

        public virtual void OnAttached(bool addDependencies)
        {
            if (addDependencies)
            {
                object[] attributes = this.GetType().GetCustomAttributes(true);

                foreach (object o in attributes)
                {
                    // components (well, any class) can be tagged with multiple attributes.. so we have to make the type check
                    if (o is ComponentDependencyAttribute)
                    {
                        ComponentDependencyAttribute cd = o as ComponentDependencyAttribute;

                        foreach (Type t in cd.Dependencies)
                        {
                            // compact framework does not contain Type.GetInterface, but only GetInterfaces
                            Type[] interfaces = t.GetInterfaces();

                            for (int j = 0; j < interfaces.Length; j++)
                            {
                                // interfaces[i].ToString() ==  Elephant.Framework.IEntityComponent
                                // interfaces[i].Name ==        IEntityComponent
                                if (interfaces[j].Name.Equals("IEntityComponent", StringComparison.InvariantCultureIgnoreCase))
                                {
                                    //IEntityComponent component = Activator.CreateInstance(t) as IEntityComponent;

                                    //owner.Add(component, false);
                                    ComponentFactory.Create(t, owner, false);

                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        public virtual void Initialize() { }

        public event EventHandler<EntityEventArgs> OwnerChanged;

        protected virtual void OnOwnerChanged(EntityEventArgs e)
        {
            if (OwnerChanged != null)
            {
                OwnerChanged(this, e);
            }
        }

        public IEntity Owner
        {
            get
            {
                return owner;
            }
            set
            {
                if (owner == null)
                {
                    owner = value;

                    OnOwnerChanged(new EntityEventArgs(value));
                }
            }
        }

        #endregion

        #region IUpdateable Members

        public event EventHandler<EventArgs> EnabledChanged;

        protected virtual void OnEnabledChanged(object sender, EventArgs args)
        {
            if (EnabledChanged != null)
            {
                EnabledChanged(this, EventArgs.Empty);
            }
        }

        public virtual void Update(GameTime gameTime) { }

        public virtual bool Enabled
        {
            get
            {
                return enabled;
            }
            set
            {
                if (enabled != value)
                {
                    enabled = value;

                    OnEnabledChanged(this, EventArgs.Empty);
                }
            }
        }

        public int UpdateOrder
        {
            get
            {
                return updateOrder;
            }
            set
            {
                if (updateOrder != value)
                {
                    updateOrder = value;

                    OnUpdateOrderChanged(EventArgs.Empty);
                }
            }
        }

        public event EventHandler<EventArgs> UpdateOrderChanged;

        protected virtual void OnUpdateOrderChanged(EventArgs e)
        {
            if (this.UpdateOrderChanged != null)
            {
                this.UpdateOrderChanged(this, e);
            }
        }

        #endregion

        #region IDisposable Members

        bool disposed;

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing && !disposed)
            {
                disposed = true;
            }
        }

        ~EntityComponent()
        {
            this.Dispose(false);
        }

        #endregion
    }
}
